
#include "netser.hpp"
#include <arpa/inet.h>
#include <cstring>
#include <iostream>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>

netser::netser(int port)
{
    int ret = 0;
    int opt = 1;

    ser_port = port;

    ser_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (ser_fd < 0) {
        std::cerr << "Create socket failed" << std::endl;
        return;
    }

    if (setsockopt(ser_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
}

netser::~netser()
{
    close(ser_fd);
}

int netser::netsend(char* buf, size_t len)
{
    int ret = 0;

    ret = send(cli_fd, buf, len, 0);
    if (ret < 0) {
        std::cerr << "Send failed, ret = " << ret << std::endl;
        return -1;
    }

    return 0;
}

int netser::netrecv(char* buf, size_t size)
{
    int ret = 0;
    socklen_t len = 0;

    ret = read(cli_fd, buf, size);
    if (ret < 0) {
        std::cerr << "Receive failed" << std::endl;
        return -1;
    } else if (0 == ret) {
        std::cerr << "Socket disconnect" << std::endl;
        return -2;
    }
    buf[ret] = '\0';

    return 0;
}

int netser::start()
{
    if (!handle.joinable()) {
        running = true;
        handle = std::thread(&netser::thread, this);
    }

    return 0;
}

int netser::stop()
{
    if (handle.joinable()) {
        running = false;
        handle.join();
    }

    return 0;
}

void netser::thread()
{
    int ret = 0;
    size_t size = 1024;
    char* buf = NULL;
    struct sockaddr_in address;
    size_t addrlen = 0;
    std::string world = "world";

    buf = new char[1024];

    addrlen = sizeof(address);
    memset(&address, 0, addrlen);
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(ser_port);
    ret = bind(ser_fd, (struct sockaddr*)&address, sizeof(address));
    if (ret < 0) {
        std::cerr << "Bind failed, ret = " << ret << std::endl;
        return;
    }

    ret = listen(ser_fd, 1);
    if (ret < 0) {
        std::cerr << "Listen failed, ret = " << ret << std::endl;
        return;
    }

    cli_fd = accept(ser_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen);
    if (cli_fd < 0) {
        std::cerr << "Accept failed, ret = " << cli_fd << std::endl;
        return;
    }

    while (running) {
        ret = netrecv(buf, size);
        if (ret < 0) {
            close(cli_fd);
            break;
        }
        std::cout << buf << std::endl;

        netsend(world.data(), world.length());
    }

    delete[] buf;
}
